// Copyright (C) 2022 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
//
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<广西木子科技有限公司>，授权编号：<NT220402151538>，代码指纹：<A.648883738.885>，技术对接人微信：<ID: Lingmuziyi>】
// 【授权寄送：<收件：李先生、地址：南宁市科园西十路11号国电智能大厦1101F、电话：17736659550、邮箱：yingshashou@vip.qq.com>】
//
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
//
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.x52im.rainbowchat.http.file.d;

import java.io.File;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import ws.schild.jave.AudioAttributes;
import ws.schild.jave.Encoder;
import ws.schild.jave.EncodingAttributes;
import ws.schild.jave.MultimediaObject;

import com.eva.epc.common.file.FileHelper;
import com.eva.epc.common.util.CommonUtils;
import com.eva.framework.httpfile.FileDownload;
import com.eva.framework.utils.LoggerFactory;
import com.x52im.rainbowchat.BaseConf;
import com.x52im.rainbowchat.http.logic.LogicUtils;
import com.x52im.rainbowchat.im.ChatServerLauncher;

/**
 * 一个图片、语音留言、个人介绍语音、相册照片等的通用下载实用类。
 * <p>
 * <b>补充：</b>下传文件时，Android、iOS、Web等都是可以在通过上传URL中将
 * 参数带过来，所以直接在HttpServletRequest里拿出url里的参数就行了。
 *
 * @since RainbowChat 2.2
 */
//FIXME: 在更苛刻的安全性要求下，可考虑要求客户端把token字段带上来，以便进行更强的合法身份检查
public class BinaryDownloader extends javax.servlet.http.HttpServlet
        implements javax.servlet.Servlet {
    /**
     * 一个1像素黑色图片
     */
    public final static String ONE_PIXEL_BLACK_FILE_NAME = "on_pixel_black.png";

    /* (non-Java-doc)
     * @see javax.servlet.http.HttpServlet#HttpServlet()
     */
    public BinaryDownloader() {
        super();
    }

    /**
     * Servlet规范中本protected方法由public void service(,,)方法调用, 而public void service(,,)
     * 则由Web容器调用(所以它是public公共方法),因此一般情况下尽量避免重写public void service(,,)方法
     * ,而重写父类的本protedted方法则比较合理.
     */
    protected void service(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, IOException {
        LoggerFactory.getLog().debug("[HTTP][BINARY_DOWN]下载2进制：你传过来的参数" +
                "action=" + req.getParameter("action")
                + ",user_uid=" + req.getParameter("user_uid") // 读取图片的人（目前服务端保留，暂未使用）
                + ",file_name=" + req.getParameter("file_name")
                + ",need_dump=" + req.getParameter("need_dump")
                + ",[---- " + req.getContextPath() + "-" + req.getRequestURL() + "]");

        String action = req.getParameter("action");
        String userUid = req.getParameter("user_uid");
        String file_name = req.getParameter("file_name");

        //【是否需要转储】：true表示需要转储，否则不需要. 转储是用于图片消息接收方在打开了该图片消息完整图后
        // * 通知服务端将此图进行转储（转储的可能性有2种：直接删除掉、移到其它存储位置），转储的目的是防止大量用户的大量图片
        // * 被读过后还存储在服务器上，加大了服务器的存储压力。<b>注意：</b><u>读取缩略图时无需转储！</u>
        String need_dump = req.getParameter("need_dump");

        // 注意：跟web互通模式开启的情况下，dump参数将强制失败，原因为web端不像app端有缓存能力，如果像app端读后
        //       就dump，则web端下次加载聊天记录时，这个图片或语音等文件就会因被转储而不存在，影响用户体验。-20190330 by Jack Jiang
        boolean needDump = (ChatServerLauncher.bridgeEnabled ? false : (need_dump != null ? "1".equals(need_dump) : false));

        try {
            // 图片聊天消息里的图片文件下载
            if ("image_d".equals(action)) {
                // 处理图片下载
                String filePath = BaseConf.getInstance().getDIR_USER_IMAGE_UPLOAD_UNREAD();
                String fullName = String.format("%s%s", BaseConf.getInstance().getDIR_USER_IMAGE_UPLOAD_UNREAD(), file_name);
                File checkFile = new File(fullName);
                if (!checkFile.exists()) {
                    fullName = String.format("%s%s", BaseConf.getInstance().getDIR_USER_IMAGE_UPLOAD_READ(), file_name);
                    checkFile = new File(fullName);
                    if (checkFile.exists()) {
                        filePath = BaseConf.getInstance().getDIR_USER_IMAGE_UPLOAD_READ();
                    }
                }
                LoggerFactory.getLog().debug("image_d === %s", fullName);

                processBinaryDownload(res, userUid, filePath, file_name, FileDownload.CONTENT_TYPE_JPEG);

                // 需要转储
                if (needDump) {
                    String imageSrcPath = BaseConf.getInstance().getDIR_USER_IMAGE_UPLOAD_UNREAD() + file_name;
                    String imageThunmbSrcPath = BaseConf.getInstance().getDIR_USER_IMAGE_UPLOAD_UNREAD() + "th_" + file_name;

                    // creates the directory if it does not exist
                    File dumpDir = new File(BaseConf.getInstance().getDIR_USER_IMAGE_UPLOAD_READ());
                    if (!dumpDir.exists())
                        dumpDir.mkdirs();

                    // 先把图片主文件copy到已读目录（TODO 2014-02-08起为了分析用户行为而转储，以后或可直接删除，因为用户的图片数据意义不大！）
                    boolean copySuccess = FileHelper.copyFile(imageSrcPath
                            , BaseConf.getInstance().getDIR_USER_IMAGE_UPLOAD_READ() + file_name);
                    // 再把缩略图copy到已读目录（TODO 2014-02-08起为了分析用户行为而转储，以后或可直接删除，因为用户的图片数据意义不大！）
                    boolean copySuccess_th = FileHelper.copyFile(imageThunmbSrcPath
                            , BaseConf.getInstance().getDIR_USER_IMAGE_UPLOAD_READ() + "th_" + file_name);
                    // 最后将图片从原目录中删除
                    if (copySuccess && copySuccess_th) {
                        FileHelper.deleteFile(imageSrcPath);
                        FileHelper.deleteFile(imageThunmbSrcPath);
                    }
                }
            }
            // 语音留言消息里的语音文件下载（AMR原文件下载）：当前主要用于APP端
            else if ("voice_d".equals(action)) {
                // 处理语音留言下载
                processBinaryDownload(res, userUid
                        , BaseConf.getInstance().getDIR_USER_VOICE_UPLOAD_UNREAD(), file_name);
                // 需要转储
                if (needDump) {
                    String voiceSrcPath = BaseConf.getInstance().getDIR_USER_VOICE_UPLOAD_UNREAD() + file_name;

                    // creates the directory if it does not exist
                    File dumpDir = new File(BaseConf.getInstance().getDIR_USER_VOICE_UPLOAD_READ());
                    if (!dumpDir.exists())
                        dumpDir.mkdirs();

                    // 先把语音留言主文件copy到已读目录（TODO 2014-02-08起为了分析用户行为而转储，以后或可直接删除，因为用户的图片数据意义不大！）
                    boolean copySuccess = FileHelper.copyFile(voiceSrcPath
                            , BaseConf.getInstance().getDIR_USER_VOICE_UPLOAD_READ() + file_name);
                    // 最后将语音留言从原目录中删除
                    if (copySuccess)
                        FileHelper.deleteFile(voiceSrcPath);
                }
            }
            // @since 4.5 - 20181206 by Jack Jiang
            // 语音留言消息里的语音文件下载（AMR转码MP3格式后的文件下载）：当前主要用于Web端
            // （因Web端html5不能支持app中广泛使用的amr音频格式，所以为了在web端能播放语音留言，只能先转码MP3后再供下载播放）
            else if ("voice_mp3_d".equals(action)) {
                String originalAMRFilePath = BaseConf.getInstance().getDIR_USER_VOICE_UPLOAD_UNREAD() + file_name;

                String destMP3FileName = file_name + ".mp3";
                String destMP3FilePath = BaseConf.getInstance().getDIR_USER_VOICE_UPLOAD_TO_MP3() + destMP3FileName;

                boolean isMP3Exists = FileHelper.isFileExist(destMP3FilePath);
                boolean isAMRExists = FileHelper.isFileExist(originalAMRFilePath);

                boolean convertFial = false;

                // mp3文件是否已经存在
                if (isMP3Exists) {
                    LoggerFactory.getLog().debug("[HTTP][BINARY_DOWN-mp3] 语音消息文件" + file_name + "的MP3转码文件已存在，无需转码，直接为用户下载之...");

                    // 处理语音留言mp3格式的下载
                    processBinaryDownload(res, userUid
                            , BaseConf.getInstance().getDIR_USER_VOICE_UPLOAD_TO_MP3()
                            , destMP3FileName
                            , FileDownload.CONTENT_TYPE_MP3);
                } else {
                    LoggerFactory.getLog().debug("[HTTP][BINARY_DOWN-mp3] 语音消息文件" + file_name
                            + "的MP3转码文件不存在，马上开始转码先..... (期望的mp3路径为：" + destMP3FilePath + ")");

                    // amr文件存在的情况下才需要转mp3，不然给空气转码？
                    if (isAMRExists) {
                        // 开始转码
                        convertFial = !convertAMRtoMP3(originalAMRFilePath, destMP3FilePath);

                        // 转码成功
                        if (!convertFial) {
                            // 处理语音留言mp3格式的下载
                            processBinaryDownload(res, userUid
                                    , BaseConf.getInstance().getDIR_USER_VOICE_UPLOAD_TO_MP3()
                                    , destMP3FileName
                                    , FileDownload.CONTENT_TYPE_MP3);
                        }
                    } else {
                        LoggerFactory.getLog().warn("[HTTP][BINARY_DOWN-mp3] 将要转码mp3的语音消息文件" + originalAMRFilePath
                                + "不存在，无法完成其对应的MP3文件转码，本次下载失败！！");
                    }
                }

                // 需要转储
                if (needDump && isAMRExists && !convertFial) {
                    // creates the directory if it does not exist
                    File dumpDir = new File(BaseConf.getInstance().getDIR_USER_VOICE_UPLOAD_READ());
                    if (!dumpDir.exists())
                        dumpDir.mkdirs();

                    // 先把语音留言主文件copy到已读目录（TODO 2014-02-08起为了分析用户行为而转储，以后或可直接删除，因为用户的图片数据意义不大！）
                    boolean copySuccess = FileHelper.copyFile(originalAMRFilePath
                            , BaseConf.getInstance().getDIR_USER_VOICE_UPLOAD_READ() + file_name);
                    // 最后将语音留言从原目录中删除
                    if (copySuccess)
                        FileHelper.deleteFile(originalAMRFilePath);
                }
            }
            // 个人照片下载
            else if ("photo_d".equals(action)) {
                // 此参数为“1”时，表示当照片图片不存在时，会默认返回一个1像素黑色图片（这主要用于改善Web网页里显示用户
                // 相册时的体验，否则当用户没有设置头像时，因为没有图片数据返回而会在页面上显示一个“破图”img元素，那就难看死了！）
                String _onePixelBlackIfNo = req.getParameter("one_pixel_black_if_no");
                boolean onePixelBlackIfNo = (_onePixelBlackIfNo != null && _onePixelBlackIfNo.equals("1"));

                File f = new File(BaseConf.getInstance().getDIR_USER_PHOTO_UPLOAD() + file_name);
                // 为web端的“破图”下载1像素黑色图片，改善视觉体验
                if (!f.exists() && onePixelBlackIfNo) {
                    File onePixelTransparentAvatarImg = new File(BinaryDownloader.class.getResource(ONE_PIXEL_BLACK_FILE_NAME).toURI());
                    FileDownload.download(res, onePixelTransparentAvatarImg, ONE_PIXEL_BLACK_FILE_NAME, FileDownload.CONTENT_TYPE_JPEG, false);
                } else {
                    // 正常处理图片下载
                    processBinaryDownload(res, userUid
                            , BaseConf.getInstance().getDIR_USER_PHOTO_UPLOAD()
                            , file_name, FileDownload.CONTENT_TYPE_JPEG);
                }

                // 如果是综略图的话就不需要尝试更新查看次数了（而且也更新不了，因为db里存放的文件名是全图而非缩略图）
                if (!file_name.startsWith("th_")) {
                    // 查看次数+1
                    LogicUtils.increaseBinaryViewCount(file_name);
                }
            }
            // 自我介绍里的语音留言文件下载
            else if ("pvoice_d".equals(action)) {
                // 处理语音留言下载
                processBinaryDownload(res, userUid, BaseConf.getInstance().getDIR_USER_PVOICE_UPLOAD(), file_name);
                // 查看次数+1
                LogicUtils.increaseBinaryViewCount(file_name);
            }
            // @since 4.5 - 20181226 by Jack Jiang
            // 自我介绍里的语音留言文件下载（AMR转码MP3格式后的文件下载）：当前主要用于Web端
            // （因Web端html5不能支持app中广泛使用的amr音频格式，所以为了在web端能播放语音留言，只能先转码MP3后再供下载播放）
            else if ("pvoice_mp3_d".equals(action)) {
                //				// 处理语音留言下载
                //				processBinaryDownload(res,  userUid
                //						, BaseConf.getInstance().getDIR_USER_PVOICE_UPLOAD(), file_name);
                //				// 查看次数+1
                //				LogicUtils.increaseBinaryViewCount(file_name);

                String originalAMRFilePath = BaseConf.getInstance().getDIR_USER_PVOICE_UPLOAD() + file_name;

                String destMP3FileName = file_name + ".mp3";
                String destMP3FilePath = BaseConf.getInstance().getDIR_USER_PVOICE_UPLOAD() + destMP3FileName;

                boolean isMP3Exists = FileHelper.isFileExist(destMP3FilePath);
                boolean isAMRExists = FileHelper.isFileExist(originalAMRFilePath);

                boolean convertFial = false;

                // mp3文件是否已经存在
                if (isMP3Exists) {
                    LoggerFactory.getLog().debug("[HTTP][BINARY_DOWN-mp3] 个人语音介绍文件" + file_name + "的MP3转码文件已存在，无需转码，直接为用户下载之...");

                    // 处理语音留言mp3格式的下载
                    processBinaryDownload(res, userUid
                            , BaseConf.getInstance().getDIR_USER_PVOICE_UPLOAD(), destMP3FileName);
                    // 查看次数+1
                    LogicUtils.increaseBinaryViewCount(file_name);
                } else {
                    LoggerFactory.getLog().debug("[HTTP][BINARY_DOWN-mp3] 个人语音介绍文件" + file_name
                            + "的MP3转码文件不存在，马上开始转码先..... (期望的mp3路径为：" + destMP3FilePath + ")");

                    // amr文件存在的情况下才需要转mp3，不然给空气转码？
                    if (isAMRExists) {
                        // 开始转码
                        convertFial = !convertAMRtoMP3(originalAMRFilePath, destMP3FilePath);

                        // 转码成功
                        if (!convertFial) {
                            // 处理语音留言mp3格式的下载
                            processBinaryDownload(res, userUid
                                    , BaseConf.getInstance().getDIR_USER_PVOICE_UPLOAD(), destMP3FileName);
                            // 查看次数+1
                            LogicUtils.increaseBinaryViewCount(file_name);
                        }
                    } else {
                        LoggerFactory.getLog().warn("[HTTP][BINARY_DOWN] 将要转码mp3的个人语音介绍文件" + originalAMRFilePath
                                + "不存在，无法完成其对应的MP3文件转码，本次下载失败！！");
                    }
                }
            }
            // 群头像的图片文件下载
            else if ("gavartar_d".equals(action)) {
                // 此参数为“1”时，表示当群组头像不存在时，会默认返回一个1像素透明图片（这主要用于改善Web网页里显示群组
                // 头像时的体验，否则当群组头像图片因种种原因没有读取成功时，没有图片数据返回而会在页面上显示一个“破图”img元素，那就难看死了！）
                String _onePixelTransparentIfNo = req.getParameter("one_pixel_transparent_if_no");
                boolean onePixelTransparentIfNo = (_onePixelTransparentIfNo != null && _onePixelTransparentIfNo.equals("1"));

                File f = new File(BaseConf.getInstance().getDIR_USER_AVATARGROUP_DIR() + file_name);
                // 为web端的“破图”下载1像素透明图片，改善视觉体验
                if (!f.exists() && onePixelTransparentIfNo) {
                    File onePixelTransparentAvatarImg = new File(BinaryDownloader.class.getResource(UserAvatarDownloader.ONE_PIXEL_TRANSPARENT_AVATAR_FILE_NAME).toURI());
                    FileDownload.download(res
                            , onePixelTransparentAvatarImg
                            , UserAvatarDownloader.ONE_PIXEL_TRANSPARENT_AVATAR_FILE_NAME
                            , FileDownload.CONTENT_TYPE_JPEG
                            , false);
                } else {
                    // 处理文件下载
                    processBinaryDownload(res, userUid, BaseConf.getInstance().getDIR_USER_AVATARGROUP_DIR(), file_name);
                }
            }
            // 位置聊天消息里的地图预览图片文件下载
            else if ("location_d".equals(action)) {
                // 处理图片下载
                processBinaryDownload(res, userUid
                        , BaseConf.getInstance().getDIR_USER_LOCATION_UPLOAD_UNREAD()
                        , file_name, FileDownload.CONTENT_TYPE_JPEG);
                // 需要转储
                if (needDump) {
                    String imageSrcPath = BaseConf.getInstance().getDIR_USER_LOCATION_UPLOAD_UNREAD() + file_name;

                    // creates the directory if it does not exist
                    File dumpDir = new File(BaseConf.getInstance().getDIR_USER_LOCATION_UPLOAD_READ());
                    if (!dumpDir.exists())
                        dumpDir.mkdirs();

                    // 先把图片主文件copy到已读目录（TODO 转储的目的权是为了分析用户行为而转储，不需要的话可直接删除，因为用户的图片数据意义不大！）
                    boolean copySuccess = FileHelper.copyFile(imageSrcPath
                            , BaseConf.getInstance().getDIR_USER_LOCATION_UPLOAD_READ() + file_name);

                    // 最后将图片从原目录中删除
                    if (copySuccess) {
                        FileHelper.deleteFile(imageSrcPath);
                    }
                }
            }
            // 好友备注中的图片下载
            // TODO: 此下载接口已写好，但因开发计划搁置，客户端暂未实现好友备注中设置图片的功能
            else if ("remark_photo_d".equals(action)) {
                // 此参数为“1”时，表示当照片图片不存在时，会默认返回一个1像素黑色图片（这主要用于改善Web网页里显示用户
                // 相册时的体验，否则当用户没有设置头像时，因为没有图片数据返回而会在页面上显示一个“破图”img元素，那就难看死了！）
                String _onePixelBlackIfNo = req.getParameter("one_pixel_black_if_no");
                boolean onePixelBlackIfNo = (_onePixelBlackIfNo != null && _onePixelBlackIfNo.equals("1"));

                File f = new File(BaseConf.getInstance().getDIR_USER_REMARK_PHOTO_UPLOAD() + file_name);
                // 为web端的“破图”下载1像素黑色图片，改善视觉体验
                if (!f.exists() && onePixelBlackIfNo) {
                    File onePixelTransparentImg = new File(BinaryDownloader.class.getResource(ONE_PIXEL_BLACK_FILE_NAME).toURI());
                    FileDownload.download(res, onePixelTransparentImg, ONE_PIXEL_BLACK_FILE_NAME, FileDownload.CONTENT_TYPE_JPEG, false);
                } else {
                    // 正常处理图片下载
                    processBinaryDownload(res, userUid, BaseConf.getInstance().getDIR_USER_REMARK_PHOTO_UPLOAD(), file_name, FileDownload.CONTENT_TYPE_JPEG);
                }
            } else {
                LoggerFactory.getLog().warn("[HTTP]无效的action=" + action);
            }
        } catch (IOException e) {
            throw e;
        } catch (Exception e2) {
            throw new IOException(e2.getMessage(), e2.getCause());
        }
    }

    /**
     * HTTP文件下载实现方法.
     * <p>
     * 本方法没有任何异常地返回即意味着成功处理完成.
     *
     * @param res
     * @param userUid
     * @param file_dir  要下载的文件所位于的服务器磁盘目录（此dir的结尾需要"/"哦）
     * @param file_name 要下载的磁盘文件名
     * @throws IOException
     */
    private void processBinaryDownload(HttpServletResponse res
            , String userUid, String file_dir, String file_name) throws Exception {
        this.processBinaryDownload(res, userUid, file_dir, file_name, FileDownload.CONTENT_TYPE_DEFAULT);
    }

    /**
     * HTTP文件下载实现方法.
     * <p>
     * 本方法没有任何异常地返回即意味着成功处理完成.
     *
     * @param res
     * @param userUid
     * @param file_dir  要下载的文件所位于的服务器磁盘目录（此dir的结尾需要"/"哦）
     * @param file_name 要下载的磁盘文件名
     * @throws IOException
     */
    private void processBinaryDownload(HttpServletResponse res
            , String userUid, String file_dir, String file_name
            , String contentType) throws Exception {
        try {
            if (!CommonUtils.isStringEmpty(file_name, true)) {
                LoggerFactory.getLog().debug("[HTTP]用户【" + userUid + "】要下载的2进制文件 " + file_name + "将立即开始处理过程 ......");
                // 实施文件下载
                FileDownload.download(res, file_dir + file_name, file_name, contentType, FileDownload.CONTENT_TYPE_JPEG.equals(contentType) ? false : true);
            } else
                LoggerFactory.getLog().warn("[HTTP]对不起,用户【" + userUid + "】要下载的2进制(file_name=" + file_name + ")不存在！");
        } catch (Exception e) {
            LoggerFactory.getLog().warn("[HTTP]用户【" + userUid + "】的下载的2进制文件不存在，本次下次已提前结束(" + e.getMessage() + ")");
        }
    }

    /**
     * 将AMR音频格式转码为MP3格式的实用方法。
     * <p>
     * 转码库使用的是ffmpeg。
     *
     * @param srcAMRPath  amr源文件绝对路径
     * @param destMP3Path 转码后要保存的mp3文件绝对路径
     * @return true表示转码和保存等工作完全完成，否则表示失败
     */
    private static boolean convertAMRtoMP3(String srcAMRPath, String destMP3Path) {
        boolean sucess = false;

        long t = System.currentTimeMillis();
        try {
            File source = new File(srcAMRPath);
            File target = new File(destMP3Path);

            AudioAttributes audio = new AudioAttributes();
            audio.setCodec("libmp3lame");
//	        audio.setBitRate(new Integer(128000));
//	        audio.setChannels(new Integer(2));
//	        audio.setSamplingRate(new Integer(44100));

            EncodingAttributes attrs = new EncodingAttributes();
            attrs.setFormat("mp3");
            attrs.setAudioAttributes(audio);

            Encoder encoder = new Encoder();
            encoder.encode(new MultimediaObject(source), target, attrs);

            sucess = true;
        } catch (Exception e) {
            LoggerFactory.getLog().warn("[AMRtoMP3] 转码失败【NO】，原因：" + e.getMessage()
                    + " [srcAMRPath=" + srcAMRPath + ", destMP3Path=" + destMP3Path + "]", e);
        }
        if (sucess) {
            LoggerFactory.getLog().info("[AMRtoMP3] 转码完成【OK】， 转码耗时：" + (System.currentTimeMillis() - t)
                    + " 毫秒  [srcAMRPath=" + srcAMRPath + ", destMP3Path=" + destMP3Path + "]。");
        }

        return sucess;
    }
}
